﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SystemAnalizer.Models;

namespace SystemAnalizer.Algorithms
{


    public class MatrixOfDiscretes
    {
        private  int row;
        private int column;
        private int tnyu;
        private double H;
        private int discretesQuantity;
        private string param;
        private DiscreteMaker discretes;
        private Matrix[] matrixDiscretes;

        public MatrixOfDiscretes(int row, int column, string param, int tnyu, double H, int discretesQuantity)
        {
            this.row                 = row;
            this.column              = column;
            this.tnyu                = tnyu;
            this.H                   = H;
            this.discretesQuantity   = discretesQuantity;
            this.param               = param;
            this.discretes = new DiscreteMaker(tnyu, H, discretesQuantity, param);

            matrixDiscretes = new Matrix[discretesQuantity];

            for (int i = 0; i < discretesQuantity; ++i)
                matrixDiscretes[i].Create(row, column);
        }
        public MatrixOfDiscretes(MatrixOfDiscretes mat)
        {
            this.row                 = mat.row;
            this.column              = mat.column;
            this.tnyu                = mat.tnyu;
            this.H                   = mat.H;
            this.discretesQuantity   = mat.discretesQuantity;
            this.param               = mat.param;
            this.discretes = new DiscreteMaker(tnyu, H, discretesQuantity, param);

            matrixDiscretes = new Matrix[discretesQuantity];

            // for (int i = 0; i < discretesQuantity; ++i)
             //   matrixDiscretes[i].Create(row, column);
             for (int i = 0; i < discretesQuantity; ++i)
                matrixDiscretes[i].Create(row, column);
            for(int i = 0; i < row; ++i)
                for(int j = 0; j < column; ++j)
                    for(int k = 0; k < discretesQuantity; ++ k)
                     {
                        this.setDiscrete(i,j,k, mat.getDiscrete(i,j,k));
                     }
        }
        public bool setDiscrete(int row, int column, String expr)
        {
            double[] disc = null;
            bool retValue = false;
            disc = discretes.calculate(expr);
            if(disc != null)
            {
                for (int k = 0; k < discretesQuantity; ++k)
                    {
                        Matrix tmp = matrixDiscretes[k];
                        matrixDiscretes[k].SetElem(row, column, disc[k]);
                        //qDebug() << disc[k];
                    }
            retValue = true;
            }
            return retValue;
        }
        public void setDiscrete(int row, int column, List<double> discrets)
        {
            if(discrets.Capacity < 0)
                return;
            for(int k = 0; k < discretesQuantity; ++k)
            {
                //matrixDiscretes[k][row][column] = discrets[k];
                matrixDiscretes[k].SetElem(row,column, discrets[k]);
            }
        }
        public void setDiscrete(int row, int column, int discrete, double value)
        {
             matrixDiscretes[discrete].SetElem(row, column, value);
        }

        public List<double> getDiscretes(int row, int column) 
        {
            List<double> tmp = new List<double>(discretesQuantity);
            for(int d = 0; d < discretesQuantity; ++d)
            {
                double val = matrixDiscretes[d].GetElem(row,column);
                tmp[d] = val;
            }
            return tmp;
        }
        public double getDiscrete(int row, int column, int discrete) 
        {
            return matrixDiscretes[discrete].GetElem(row, column);
        }

        public List<double> Multiply(int row, int column, List<double> discrets) 
        {
            if(discrets == null)
                return null;
            List<double> tmpDiscrets = new List<double>(this.discretesQuantity);
            for(int k = 0; k < discretesQuantity; ++k)
            {
                for(int l = 0; l <= k; ++l)
                 {
                tmpDiscrets[k] += matrixDiscretes[l].GetElem(row,column) * discrets[k-l];
            }
        }
        return tmpDiscrets;
    }
        /*
    MatrixOfDiscretes operator*(MatrixOfDiscretes mat1, MatrixOfDiscretes mat2)
    {
        MatrixOfDiscretes tmpMatrixDiscretes = new MatrixOfDiscretes(row, mat1.column, param, tnyu, H, discretesQuantity);
        tmpMatrixDiscretes = mat1;
        for(int k = 0; k < discretesQuantity; ++k)
        {
            tmpMatrixDiscretes.matrixDiscretes[k].Zeros();
            for(int l = 0; l <= k; ++l)
            {
                tmpMatrixDiscretes.matrixDiscretes[k] += mat1.matrixDiscretes[l] * mat2.matrixDiscretes[k-l];
            }
        }
        return tmpMatrixDiscretes;
    }
         */
        /*
 MatrixOfDiscretes operator=( MatrixOfDiscretes mat)
    {
        //mat.show();
        if(mat == this)
            return this;
        row                 = mat.row;
        column              = mat.column;
        tnyu                = mat.tnyu;
        H                   = mat.H;
        discretesQuantity   = mat.discretesQuantity;
        param               = mat.param;
        discretes = new D(tnyu, H, discretesQuantity, param);

        matrixDiscretes = new Matrix_double[discretesQuantity];

        for (int i = 0; i < discretesQuantity; ++i)
            matrixDiscretes[i].Create(row, column);

        for(int i = 0; i < row; ++i)
            for(int j = 0; j < column; ++j)
                for(int k = 0; k < discretesQuantity; ++ k)
                {
                    this->setDiscrete(i,j,k, mat.getDiscrete(i,j,k));
                }
        //show();
        return this;
    }
         */
    public Matrix  getMatrixForDiscret (int discreteIndex)
    {
        return matrixDiscretes[discreteIndex];
     }

    public MatrixOfDiscretes Multiply(MatrixOfDiscretes mat)
    {
        MatrixOfDiscretes tmpMatrixDiscretes = new MatrixOfDiscretes(row, mat.column, param, tnyu, H, discretesQuantity);
        tmpMatrixDiscretes = mat;
        for (int k = 0; k < discretesQuantity; ++k)
        {
            tmpMatrixDiscretes.matrixDiscretes[k].Zeros();
            for (int l = 0; l <= k; ++l)
            {
                tmpMatrixDiscretes.matrixDiscretes[k] += matrixDiscretes[l] * mat.matrixDiscretes[k - l];
            }
        }
        return tmpMatrixDiscretes;
    }
public List<double> Multiply(List<double> discrets, int row, int column) 
{
    if(discrets == null)
        return new List<double>();
    List<double> tmpDiscrets = new List<double>(discretesQuantity);
    for(int k = 0; k < discretesQuantity; ++k)
    {
        tmpDiscrets[k] = 0;
        for(int l = 0; l <= k; ++l)
        {
            tmpDiscrets[k] += matrixDiscretes[l].GetElem(row,column) * discrets[k-l];
        }
    }
    return tmpDiscrets;
}

public List<double> Multiply(List<double> discrets1, List<double> discrets2)
{
    if(discrets1 == null || discrets2 == null)
        return new List<double>();
    List<double> tmpDiscrets = new List<double>(discretesQuantity);
    for(int k = 0; k < discretesQuantity; ++k)
    {
        tmpDiscrets[k] = 0;
        for(int l = 0; l <= k; ++l)
        {
            tmpDiscrets[k] += discrets1[l] * discrets2[k-l];
        }
    }
    return tmpDiscrets;
}
public List<double> Multiply(int row1, int column1, int row2, int column2) 
{
    List<double> tmpDiscrets = new List<double>(discretesQuantity);
    for(int k = 0; k < discretesQuantity; ++k)
    {
        for(int l = 0; l <= k; ++l)
        {
            tmpDiscrets[k] += matrixDiscretes[l].GetElem(row1,column1) * matrixDiscretes[k-l].GetElem(row2,column2);
        }
    }
    return tmpDiscrets;
}
public List<double> Divide(int row, int column, List<double> discrets) 
{
    List<double> tmpDiscrets = new List<double>(discretesQuantity);
    if(discrets[0] == 0)
        return new List<double>();
    for(int k = 0; k < discretesQuantity; ++k)
    {
        tmpDiscrets[k] = matrixDiscretes[k].GetElem(row,column);
        for(int l = 1; l <= k; ++l)
        {
            tmpDiscrets[k] -= matrixDiscretes[l].GetElem(row,column) * discrets[k-l];
        }
        tmpDiscrets[k] = tmpDiscrets[k] / discrets[0];
    }
    return tmpDiscrets;
}

public List<double> Divide(int row1, int column1, int row2, int column2) 
{
    List<double> tmpDiscrets = new List<double>(discretesQuantity);
    if(matrixDiscretes[0].GetElem(row2,column2)== 0)
        return new List<double>();
    for(int k = 0; k < discretesQuantity; ++k)
    {
        tmpDiscrets[k] = matrixDiscretes[k].GetElem(row1,column1);
        for(int l = 1; l <= k; ++l)
        {
            tmpDiscrets[k] -= tmpDiscrets[k-l] * matrixDiscretes[l].GetElem(row2,column2);
        }
        tmpDiscrets[k] = tmpDiscrets[k] / matrixDiscretes[0].GetElem(row2,column2);
    }
    return tmpDiscrets;
}
public List<double> Divide(List<double> discrets, int row2, int column2) 
{
    List<double> tmpDiscrets = new List<double>(discretesQuantity);
    if(matrixDiscretes[0].GetElem(row2,column2) == 0)
        return new List<double>();
    for(int k = 0; k < discretesQuantity; ++k)
    {
        tmpDiscrets[k] = discrets[k];
        for(int l = 1; l <= k; ++l)
        {
            tmpDiscrets[k] -= tmpDiscrets[k-l] * matrixDiscretes[l].GetElem(row2,column2);
        }
        tmpDiscrets[k] = tmpDiscrets[k] / matrixDiscretes[0].GetElem(row2,column2);
    }
    return tmpDiscrets;
}

public void SwapRows(int row1, int row2)
{
    for(int j =  0; j < column; ++j )
    {
        for(int k = 0; k < discretesQuantity; ++k)
        {
            double d = getDiscrete(row1, j, k);
            setDiscrete(row1, j, k, getDiscrete(row2, j, k) );
            setDiscrete(row2, j, k, d );
        }
    }
}
public void SwapColumns(int column1, int column2)
{
    for(int i =  0; i < row; ++i )
    {
        for(int k = 0; k < discretesQuantity; ++k)
        {
            double d = getDiscrete(i, column1, k);
            setDiscrete(i, column1, k, getDiscrete(i, column2, k) );
            setDiscrete(i, column2, k, d );
        }
    }
}
public List<double> Minus(int row1, int column1, int row2, int column2) 
{
    List<double> tmpDiscrets = new List<double>(discretesQuantity);
    for(int k = 0; k < discretesQuantity; ++k)
    {
        tmpDiscrets[k] = matrixDiscretes[k].GetElem(row1,column1) - matrixDiscretes[k].GetElem(row2,column2);
    }
    return tmpDiscrets;
}

public MatrixOfDiscretes Zeros()
    {
        for(int i = 0; i < getRowCount(); ++i)
        {   
            for(int j = 0; j < getColumnCount(); ++j)
            {
                for(int k = 0; k < discretesQuantity; ++k )
                    setDiscrete(i, j, k, 0);
            }
        }
    //this->show();
        return this;
    }
public MatrixOfDiscretes E()
    {
        this.Zeros();
        //this.show();
        for (int i = 0; i < getRowCount(); i++)
        {
        setDiscrete(i, i, 0, 1);
        for(int k = 1; k < discretesQuantity; ++k)
                setDiscrete(i, i, k, 0);
        }
        //this->show();
        return this;
    }

public int getRowCount() 
    {
        return row;
    }
public int getDiscretesQuantity() 
    {
        return discretesQuantity;
    }
public int getColumnCount()
    {
        return column;
    }


};
}
